#pragma once
#include "common.h"

class CTPTrader;

struct UserInfo;

struct InvestorInfo : public tagCTPInvestorInfo
{
	UserInfo* parent = nullptr;
	HZQDB h = nullptr;

	InvestorInfo(UserInfo* parent);
};

struct AccountInfo : public tagCTPAccountInfo
{
	UserInfo* parent = nullptr;
	std::shared_ptr<CTPAccountInfo> sp;
	HZQDB h = nullptr;

	AccountInfo(UserInfo* parent);
};

struct PositionInfo : public tagPositionInfo
{
	UserInfo* parent = nullptr;
	std::shared_ptr<CTPPositionInfo> sp;
	HZQDB hcode = nullptr;
	HZQDB h = nullptr;

	void update();
};

struct OrderInfo : public tagOrderInfo
{
	UserInfo* parent = nullptr;
	std::shared_ptr<CTPOrderInfo> sp;
	HZQDB hcode = nullptr;
	HZQDB h = nullptr;

	void update();
};

struct TradeInfo : public tagTradeInfo
{
	UserInfo* parent = nullptr;
	std::shared_ptr<CTPTradeInfo> sp;
	HZQDB hcode = nullptr;
	HZQDB h = nullptr;

	void update();
};

struct UserInfo : public tagCTPUserInfo
{
	HZQDB h = nullptr;
	std::shared_ptr<InvestorInfo> investor;
	std::shared_ptr<AccountInfo> account;
	std::map<const char*, std::shared_ptr<PositionInfo>, XUtil::strless> long_positions;
	std::map<const char*, std::shared_ptr<PositionInfo>, XUtil::strless> short_positions;
	std::map<const char*, std::shared_ptr<OrderInfo>, XUtil::strless> orders;
	std::map<const char*, std::shared_ptr<TradeInfo>, XUtil::strless> trades;

	UserInfo();

	void clear();

	void update_investor(const CThostFtdcInvestorField& investor);
	void update_account(std::shared_ptr<CTPAccountInfo> account);

	std::shared_ptr<PositionInfo> update_position(std::shared_ptr<CTPPositionInfo> sp);
	std::shared_ptr<OrderInfo> update_order(std::shared_ptr<CTPOrderInfo> sp);
	std::shared_ptr<TradeInfo> update_trade(std::shared_ptr<CTPTradeInfo> sp);
};

class CTPTrader
	: public CThostFtdcTraderSpi
	, public XUtil::XStateEx<CTP_STAT_MAX + 1>
	, public zqdb::NotifyImplExT<CTPTrader>
	, public std::enable_shared_from_this<CTPTrader>
{
	friend class Manager;
	friend class MDMgr;
	friend class TDMgr;
	typedef CTPTrader This;
	typedef CThostFtdcTraderSpi Base;
	typedef zqdb::NotifyImplExT<CTPTrader> NotifyBase;
protected:
	bool base_flag_ = false; //是否基础交易，基础交易需要查询代码基础信息
	bool stop_flag_ = false;
	boost::asio::io_service& service_;
	boost::asio::deadline_timer timer_;
	CThostFtdcTraderApi* api_ = nullptr;
	zqdb::Msg req_login_; //请求登录消息
	CTPUserLoginInfo userinfo_;
	std::string userid_;
	enum {
		FIRST_LOGIN_LOGING = 0,
		FIRST_LOGIN_SUCESS,
		FIRST_LOGIN_FAILED,
	};
	int first_login_flag_ = FIRST_LOGIN_LOGING;

	std::chrono::system_clock::time_point login_time_;

	CThostFtdcRspAuthenticateField m_AuthInfo = { 0 }; //身份认证信息
	CThostFtdcRspUserLoginField m_UserInfo = { 0 };	//登录信息
	int m_OrderRef = 0;

	CThostFtdcInvestorField m_InvestorInfo = { 0 }; //投资者信息
	//CThostFtdcTradingAccountField m_TradingAccount; //交易资金账户信息
	CThostFtdcTradingCodeField m_TradingCode = { 0 }; //交易编码

	CThostFtdcSettlementInfoField m_SettlementInfo = { 0 }; //结算单信息
	CThostFtdcSettlementInfoConfirmField m_SettlementConfirm = { 0 }; //结算单确认

	//CThostFtdcNoticeField m_NoticeInfo = { 0 };	//通知
	//CThostFtdcCFMMCTradingAccountKeyField m_CFMMCKeyInfo = { 0 }; //保证金监管系统经纪公司资金账户密钥

	bool init_flag_ = false;
	std::map<const char*, std::shared_ptr<CTPExchangeInfoEx>, XUtil::strless> ctp_exchanges_;
	std::map<const char*, std::shared_ptr<CTPProductInfoEx>, XUtil::strless> ctp_products_;
	std::map<const char*, std::shared_ptr<CTPCommodityInfoEx>, XUtil::strless> ctp_commoditys_;
	//std::map<const char*, std::array<std::shared_ptr<CTPCommodityInfoEx>,12>, XUtil::strless> product_commiditys_;
	//
	std::shared_ptr<CTPAccountInfo> account_;
	std::map<std::string, std::shared_ptr<CTPOrderInfo>> orders_;
	std::map<std::string, std::shared_ptr<CTPTradeInfo>> trades_;
	std::map<std::string, std::shared_ptr<CTPPositionInfo>> long_positions_;
	std::map<std::string, std::shared_ptr<CTPPositionInfo>> short_positions_;
	//
	std::shared_ptr<UserInfo> user_;
	//
	std::vector<CThostFtdcInstrumentStatusField> init_status_; //临时保存初始状态变更记录，初始化市场、产品、商品后再更新状态
	//
	uint32_t test_date_ = 0;
	uint32_t test_time_ = 0;													   //
public:
	CTPTrader(bool base_flag, boost::asio::io_service& service);

	bool start(char* xml, int xmlflag = 0);
	bool start(zqdb::Msg& msg);
	void update(zqdb::Msg& msg);
	void stop();

	inline bool is_base() { return base_flag_; }
	inline bool is_stop() { return stop_flag_; }
	inline bool is_test(const char* broker = nullptr) {
		if (broker) {
			return strcmp(userinfo_.BrokerID, broker) == 0;
		}
		return ZQDBIsTest()
			|| strcmp(userinfo_.BrokerID, ZQDB_USER_BROKER_MOCK) == 0
			|| strcmp(userinfo_.BrokerID, ZQDB_USER_BROKER_TEST) == 0
			;
	}
	inline bool is_removable() { return !base_flag_ && first_login_flag_ != FIRST_LOGIN_SUCESS; }

	inline boost::asio::io_service& service() { return service_; }

	inline const CTPUserLoginInfo& userinfo() { return userinfo_; }
	inline const std::chrono::system_clock::time_point login_time() { return login_time_; }
	inline const CThostFtdcRspUserLoginField& rsp_logininfo() { return m_UserInfo; }
	
	inline const CThostFtdcInvestorField& investorinfo() { return m_InvestorInfo; }
	inline const CThostFtdcTradingCodeField& tradingcode() { return m_TradingCode; }

	void on_update(HZQDB hcode);

	int request(zqdb::Msg& msg);

protected:
	void register_timer_for_reconnect();
	void register_timer_for_requery();
	void register_timer_for_refresh();
	void unregister_timer();

protected:
	//以下是当前service线程回调函数
	void set_online();

	void set_offline();

	void on_clear_new_tradingday();
	void on_init_new_tradingday();
	void on_end_new_tradingday();
	void on_request(int reqid);

	void do_login_err_response(int err, const char* msg);
	void do_login_response(const char* msg);

	void do_err_response(int reqid, int err, const char* msg);
	void do_response(int reqid, const char* key, const char* value);

	void on_mock_order_insert(const CThostFtdcInputOrderField& req);
	void on_mock_order_cancel(const CThostFtdcInputOrderActionField& req, std::shared_ptr<CTPOrderInfo> order);

	void mock_update_order(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order
		, TThostFtdcOrderStatusType OrderStatus, TThostFtdcVolumeType VolumeTraded = 0);
	void mock_new_trade(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order
		, TThostFtdcPriceType Price, TThostFtdcVolumeType Volume);
	void mock_queue(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order); //
	void mock_cancel(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order);
	void mock_match(zqdb::CodeT<CTPCODEINFO>& code, std::shared_ptr<CTPOrderInfo>& order); //

	void on_timer_for_reconnect(const boost::system::error_code& ec);
	void on_timer_for_requery(const boost::system::error_code& ec);
	void on_timer_for_refresh(const boost::system::error_code& ec);

	void clear();

	void on_connect();

	void on_disconnect();

	inline int NextOrderRef() { return ++m_OrderRef; }
	int NextRequestID();
	bool IsNeedRequestAndSet(int nStatus);

	void on_init_done(int status);

	void on_init_next();

	void on_authenticate(const CThostFtdcRspAuthenticateField& rspAuthenticateField, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_login(const CThostFtdcRspUserLoginField& rspUserLogin, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_add_settlement(const CThostFtdcSettlementInfoField& settlementInfo, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_settlement_confirm(const CThostFtdcSettlementInfoConfirmField& settlementInfoConfirm, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_add_settlement_confirm(const CThostFtdcSettlementInfoConfirmField& settlementInfoConfirm, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_add_investor(const CThostFtdcInvestorField& investor, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_add_trading_code(const CThostFtdcTradingCodeField& tradingCode, const CThostFtdcRspInfoField& rspInfo, bool bIsLast);

	void on_add_exchange(const std::shared_ptr<CTPExchangeInfoEx>& exchange);

	void on_add_product(const std::shared_ptr<CTPProductInfoEx>& product);

	void on_add_commodity(const std::shared_ptr<CTPCommodityInfoEx>& commodity);

	void on_market_data_init(const CThostFtdcDepthMarketDataField& data);

	void on_add_commission_rate(const CThostFtdcInstrumentCommissionRateField& commission);

	void on_init_account(const std::shared_ptr<CTPAccountInfo>& account);

	void on_add_order(const std::shared_ptr<CTPOrderInfo>& order);

	void on_add_trade(const std::shared_ptr<CTPTradeInfo>& trade);

	void on_add_position(const std::shared_ptr<CTPPositionInfo>& position);

	void reg_notify(HZQDB h);
	void unreg_notify();

	void on_test_login();
	void on_test_init();
	void on_test_normal();

	void on_normal();

	void on_market_data_udpate(const CThostFtdcDepthMarketDataField& data);

	void on_market_status_update(const CThostFtdcInstrumentStatusField& status);

	void on_rsp_account(const std::shared_ptr<CTPAccountInfo>& account, bool is_last);

	void on_rsp_order(const std::shared_ptr<CTPOrderInfo>& order, bool is_last);

	void on_rsp_trade(const std::shared_ptr<CTPTradeInfo>& trade, bool is_last);

	void on_rsp_position(const std::shared_ptr<CTPPositionInfo>& position, bool is_last);

	void on_account_update();

	void on_order_update(const std::shared_ptr<CTPOrderInfo>& order);

	void on_trade_update(const std::shared_ptr<CTPTradeInfo>& trade);

	void on_position_update(const std::shared_ptr<CTPPositionInfo>& position);

	void on_rsp_error();

	void on_rsp_order_send(const CThostFtdcInputOrderField& req, const CThostFtdcRspInfoField& rsp_info, int req_id);

	void on_rsp_order_cancel(const CThostFtdcInputOrderActionField& req, const CThostFtdcRspInfoField& rsp_info, int req_id);

	void on_err_order_send(const CThostFtdcInputOrderField& req);

	void on_err_order_cancel(const CThostFtdcOrderActionField& req);

	void on_rtn_order(const std::shared_ptr<CTPOrderInfo>& order);

	void on_rtn_trade(const std::shared_ptr<CTPTradeInfo>& trade);

protected:

	//以下是来自交易回调

	///当客户端与交易后台建立起通信连接时（还未登录前），该方法被调用。
	virtual void OnFrontConnected();

	///当客户端与交易后台通信连接断开时，该方法被调用。当发生这个情况后，API会自动重新连接，客户端可不做处理。
	///@param nReason 错误原因
	///        0x1001 网络读失败
	///        0x1002 网络写失败
	///        0x2001 接收心跳超时
	///        0x2002 发送心跳失败
	///        0x2003 收到错误报文
	virtual void OnFrontDisconnected(int nReason);

	///客户端认证响应
	virtual void OnRspAuthenticate(CThostFtdcRspAuthenticateField *pRspAuthenticateField, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///登录请求响应
	virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///登出请求响应
	//virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRspUserPasswordUpdate(CThostFtdcUserPasswordUpdateField *pUserPasswordUpdate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRspTradingAccountPasswordUpdate(CThostFtdcTradingAccountPasswordUpdateField *pTradingAccountPasswordUpdate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRspQryExchange(CThostFtdcExchangeField *pExchange, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRspQryProduct(CThostFtdcProductField *pProduct, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRspQryInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRspQryDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	void OnRtnInstrumentStatus(CThostFtdcInstrumentStatusField *pInstrumentStatus);

	///请求查询合约手续费率响应
	virtual void OnRspQryInstrumentCommissionRate(CThostFtdcInstrumentCommissionRateField *pInstrumentCommissionRate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询资金账户响应
	virtual void OnRspQryTradingAccount(CThostFtdcTradingAccountField *pTradingAccount, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询投资者结算结果响应
	virtual void OnRspQrySettlementInfo(CThostFtdcSettlementInfoField *pSettlementInfo, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///投资者结算结果确认响应
	virtual void OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询结算信息确认响应
	virtual void OnRspQrySettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询投资者响应
	virtual void OnRspQryInvestor(CThostFtdcInvestorField *pInvestor, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询交易编码响应
	virtual void OnRspQryTradingCode(CThostFtdcTradingCodeField *pTradingCode, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询报单响应
	virtual void OnRspQryOrder(CThostFtdcOrderField *pOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询成交响应
	virtual void OnRspQryTrade(CThostFtdcTradeField *pTrade, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///请求查询投资者持仓响应
	virtual void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///报单操作请求响应
	virtual void OnRspOrderAction(CThostFtdcInputOrderActionField *pInputOrderAction, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///报单录入请求响应
	virtual void OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///错误应答
	virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///报单通知
	virtual void OnRtnOrder(CThostFtdcOrderField *pOrder);

	///成交通知
	virtual void OnRtnTrade(CThostFtdcTradeField *pTrade);

	///报单录入错误回报
	virtual void OnErrRtnOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo);

	///报单操作错误回报
	virtual void OnErrRtnOrderAction(CThostFtdcOrderActionField *pOrderAction, CThostFtdcRspInfoField *pRspInfo);

	///查询最大报单数量响应
	virtual void OnRspQueryMaxOrderVolume(CThostFtdcQueryMaxOrderVolumeField *pQueryMaxOrderVolume, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

};

class TDMgr : public XUtil::XService, public zqdb::NotifyImplT<TDMgr>
{
	friend class Manager;
	typedef TDMgr This;
	typedef XUtil::XService Base;
	typedef zqdb::NotifyImplT<TDMgr> NotifyBase;
protected:
	bool stop_flag_ = false;
	boost::asio::deadline_timer timer_;
	//
	size_t MaxUserCount_ = 0;
	size_t MaxInvestorCount_ = 0;
	size_t MaxAccountCount_ = 0;
	size_t MaxPositionCount_ = 0;
	size_t MaxOrderCount_ = 0;
	size_t MaxTradeCount_ = 0;
	//交易相关
	std::map<std::string, std::shared_ptr<CTPTrader>> traders_;
	std::mutex mutex_;
	std::shared_ptr<zqdb::AllTableData> users_;
	std::shared_ptr<zqdb::AllTableData> investors_;
	std::shared_ptr<zqdb::AllTableData> accounts_;
	std::shared_ptr<zqdb::AllTableData> orders_;
	std::shared_ptr<zqdb::AllTableData> trades_;
	std::shared_ptr<zqdb::AllTableData> positions_;
	HZQDB htb_commission_rate_ = nullptr;
	//
	bool normal_flag_ = false;
protected:
	void unregister_timer();
public:
	static TDMgr& Inst()
	{
		static TDMgr s_inst;
		return s_inst;
	}

	TDMgr();

	//公共函数
	inline bool is_stop() { return stop_flag_; }
	inline bool is_normal() { return normal_flag_; }

	//外部调用
	void init();
	bool start();
	void run();
	void stop();

	void HandleNotify(HZQDB h, ZQDB_NOTIFY_TYPE notify);

	int request(zqdb::Msg& msg);

	std::shared_ptr<CTPTrader> find_trader(const std::string& user);
	void add_trader(const std::string& user, std::shared_ptr<CTPTrader> trader);
	bool remove_trader(const std::string& user, std::shared_ptr<CTPTrader>* trader = nullptr);

	//内部调用

	void on_normal(bool new_trading_day);

	HZQDB find_trader(tagCTPUserInfo* user);
	HZQDB update_user(HZQDB h, tagCTPUserInfo* user);
	HZQDB update_investor(HZQDB h, tagCTPInvestorInfo* investor);
	HZQDB update_account(HZQDB h, tagCTPAccountInfo* account);
	HZQDB update_order(HZQDB h, tagOrderInfo* order);
	HZQDB update_trade(HZQDB h, tagTradeInfo* trade);
	HZQDB update_position(HZQDB h, tagPositionInfo* position);

	//内部回调
	void begin_new_tradingday(std::promise<int>* promise);
	void begin_new_tradingday();
	void clear_new_tradingday(std::promise<int>* promise);
	void clear_new_tradingday();
	void init_new_tradingday(std::promise<int>* promise);
	void init_new_tradingday();
	void end_new_tradingday(std::promise<int>* promise);
	void end_new_tradingday();
};
